package fr.upmc.aladyn.client;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.NotFoundException;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import fr.upmc.aladyn.interfaces.IPerson;
import fr.upmc.aladyn.interfaces.IPointDistance;
import fr.upmc.aladyn.interfaces.IStringable;
import fr.upmc.aladyn.interfaces.IXMLRMIField;
import fr.upmc.aladyn.interfaces.IXMLRMISerializable;
import fr.upmc.aladyn.tools.ObjectParamTools;

public class PointDistanceParam extends ObjectParam implements IXMLRMISerializable, IPointDistance{

	
	@IXMLRMIField(serializationName="x",serializationType="object")
	protected PointParam a;
	@IXMLRMIField(serializationName="y",serializationType="object")
	protected PointParam b;
	@IXMLRMIField(serializationName="distance",serializationType="double")
	public double distance;
	
	public PointDistanceParam(PointParam a, PointParam b) {
		this.a= a;
		this.b= b;
		this.distance=0.0;
	}
	
	public double calculDistance() {
		this.distance= Math.sqrt(((this.b.a - this.a.a)*(this.b.a - this.a.a))+((this.b.b - this.a.b)*(this.b.b - this.a.b)));
		return distance;
	}
	
//	public void seta(double a) {
//		this.a = a;
//	}
	
	public void setdistance(double distance) {this.distance = distance;}
	
	
	public String toXML(Class<?> inter) {
		
		try {
			if(!inter.isInterface())
				throw new Exception();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		
		ClassPool pool = ClassPool.getDefault();
		CtClass objectParamCtClass = null;
		
		try {
			objectParamCtClass = pool.get("fr.upmc.aladyn.client.PointDistanceParam");
		} catch (NotFoundException e) {e.printStackTrace();}
		
		boolean OK = false;
		CtClass interfaces[] = null;
		try {
			interfaces = objectParamCtClass.getInterfaces();
		} catch (NotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		for(CtClass interfaze : interfaces) {
			
			if(interfaze.getName().equals(inter.getName())) {
				OK = true;
				break;
			}
		}
		
		try {
			if(!OK)
				throw new Exception();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		
		StringBuffer buffer = new StringBuffer();
		
	    	buffer.append("<object oid=\""+oid+"\">\n");
	    	buffer.append("<fields>\n");
	    	
	    	CtField [] fields = null;
	    	
			fields = objectParamCtClass.getDeclaredFields();
			
			for(CtField field : fields) {
				if(field.getName().equals("oid"))
					continue;				
				Object annotation = null;
				try {
					annotation = field.getAnnotations()[0];
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		    	
		    	if(annotation instanceof IXMLRMIField) {
		    			IXMLRMIField xmlRMIanno = (IXMLRMIField) annotation;
		    			//System.out.println("field name = "+a);
		    			buffer.append("<field name=\"" + xmlRMIanno.serializationName()+"\"> <value>");
		    			if(xmlRMIanno.serializationType().equals("object")){
		    				
		    				if(xmlRMIanno.serializationName().equals("x")){
		    					 //pointParamToXml (buffer,  this.getA());
		    					 buffer.append(a.toXML(null));
		    				}
		    				else if(xmlRMIanno.serializationName().equals("y")){
		    					 //pointParamToXml(buffer, this.getB());
		    					 buffer.append(b.toXML(null));	
		    				}
		    				
		    			}
		    			else
		    			{
		    				buffer.append("<"+xmlRMIanno.serializationType()+">");
		    				buffer.append(distance);
		    				buffer.append("</"+xmlRMIanno.serializationType()+">");
		    				
		    			}
		    			
		    			buffer.append("</value> \n </field> \n");
		    		}
				
			}
			
			buffer.append("</fields>\n");
	    	buffer.append("<methods>\n");
	    	
	    	Method[] interMethods = inter.getDeclaredMethods();
			for(Method method : interMethods) {
				if(method.getName().equals("calculDistance")) {
					buffer.append("<method language=\"Java\">\n");
			    	buffer.append("public double calculDistance()\n");
			    	buffer.append("{\n");
			    	buffer.append("this.distance = java.lang.Math.sqrt(((this.y.getxField() - this.x.getxField())*(this.y.getxField() - this.x.getxField())+((this.y.getyField() - this.x.getyField())*(this.y.getyField() - this.x.getyField()))));\n");
			    	buffer.append("return this.distance ;");
			    	buffer.append("}\n");
			    	buffer.append("</method>");					
				}
			}
	    	
	    	buffer.append("</methods>\n");
	    	buffer.append("</object>\n");
	    
		return buffer.toString();
	}
	
	public void updateFromXML(Element theXML) {
		
		NodeList nl = theXML.getElementsByTagName("object");
		
		a.updateFromXML((Element) nl.item(0));
		b.updateFromXML((Element) nl.item(1));
		String distanceStringValue = theXML.getElementsByTagName("field").item(8).getTextContent();
		ObjectParamTools.invokeMethod(this, "setdistance", new Class [] {double.class}, new Object [] {(double)Double.parseDouble(distanceStringValue)});
	}
	
	
	
	
}
